package com.qzsoft.zhjd.server.socket;

import java.nio.charset.Charset;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import com.qzsoft.zhjd.server.socket.config.TcpReceiveConfig;
import com.qzsoft.zhjd.server.socket.handler.TcpReceiveLoginHandler;
import com.qzsoft.zhjd.server.socket.handler.TcpReceiveMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName TcpReceiveServer
 * @Description 数据接收服务
 * @author linhuawei
 * @since 2022-01-12
 */
@Slf4j
@Component
public class TcpReceiveServer {

    private ServerBootstrap serverBootstrap;

    private ChannelFuture channelFuture;

    @Autowired
    private TcpReceiveConfig tcpReceiveConfig;

    @Autowired
    private TcpReceiveLoginHandler tcpReceiveLoginHandler;

    @Autowired
    private TcpReceiveMessageHandler tcpReceiveMessageHandler;

    @PostConstruct
    public void start() {
        // 判断是否启用
        if (!tcpReceiveConfig.isEnable()) {
            return;
        }

        // 创建socket服务器
        ChannelInitializer<SocketChannel> tcpChannelInitializer = new ChannelInitializer<SocketChannel>() {
            protected void initChannel(final SocketChannel ch) throws Exception {
                final ChannelPipeline channelPipeline = ch.pipeline();
                channelPipeline.addLast("loginHandler", tcpReceiveLoginHandler);
                channelPipeline.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));
                channelPipeline.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));
                channelPipeline.addLast("messageHandler", tcpReceiveMessageHandler);
            }
        };
        serverBootstrap = new ServerBootstrap();
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(tcpReceiveConfig.getBossCount());
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(tcpReceiveConfig.getWorkerCount());
        serverBootstrap.group(bossGroup, workerGroup);
        serverBootstrap.channel((Class<? extends ServerChannel>) NioServerSocketChannel.class);
        serverBootstrap.childHandler((ChannelHandler) tcpChannelInitializer);
        serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, tcpReceiveConfig.getSoKeeplive());
        serverBootstrap.option(ChannelOption.SO_BACKLOG, tcpReceiveConfig.getSoBacklog());

        try {
            channelFuture = serverBootstrap.bind(tcpReceiveConfig.getPort()).sync().addListener(future -> {
                if (future.isSuccess()) {
                    log.info("服务器启动成功:port = {}", tcpReceiveConfig.getPort());
                } else {
                    log.info("服务器启动失败:port = {}", tcpReceiveConfig.getPort());
                }
            });
        } catch (InterruptedException e) {
            log.info("服务器启动异常:port = {}, ex = {}", tcpReceiveConfig.getPort(), e.getMessage());
        }
    }

    @PreDestroy
    public void close() {
        // 判断是否启用
        if (!tcpReceiveConfig.isEnable()) {
            return;
        }

        // 关闭socket服务器
        try {
            if (null != this.channelFuture) {
                this.channelFuture.channel().close().sync().addListener(future -> {
                    if (future.isSuccess()) {
                        log.info("服务器关闭成功");
                    } else {
                        log.info("服务器关闭失败");
                    }
                });
            }
        } catch (InterruptedException e) {
            log.info("服务器关闭异常: ex = {}", e.getMessage());
        } finally {
            serverBootstrap.config().group().shutdownGracefully();
            serverBootstrap.config().childGroup().shutdownGracefully();
        }
    }

}
